﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Csla.Data;
using System.Data.SqlClient;
using Csla.Core;
using Csla.Server;

namespace Csla
{
    [Serializable]
    public class GBusinessOrderedTreeListBase<TList, TModel> : GBusinessListBase<TList, TModel>
        , IOrderedTreeNodeCollection<TModel>
        , ISimpleMovableCollection<TModel>
        where TList : GBusinessOrderedTreeListBase<TList, TModel>
        where TModel : BusinessBase, Core.IEditableBusinessObject, IOrderedObject, ITreeNode
    {
        public GBusinessOrderedTreeListBase()
        {
            //默认初始为没有排序的。（数据库查询出来的数据。如果想提升性能，则可以设置为true）
            this.Sorted = false;
            this.ObjectRelationsRuilt = false;
        }

        #region 单向依赖，从上到下是依赖关系。

        #region IOrderedTreeNodeCollection<C> Members

        public void EnsureIndices()
        {
            if (this.Sorted == false)
            {
                //physical index
                this.EnsureSorted();

                //logical index equals physical index
                //这步比较浪费，所以假定是有序的。客户程序必须自行保证这点。
                //暂时打开
                this.SetOrderNoByIndex();
            }
        }
        public void SetOrderNoByTree()
        {
            this.EnsureObjectRelations();

            var roots = TreeHelper.FindRootNodes(this);

            int orderNo = 0;
            foreach (var item in roots)
            {
                TreeHelper.TravelDepthFirst(item, n =>
                {
                    (n as IOrderedObject).OrderNo = orderNo;
                    orderNo++;
                });
            }
        }
        public void MoveNode(ITreeNode node, bool isUp)
        {
            if (node == null) throw new ArgumentNullException("node");
            this.EnsureIndices();

            var currentObject = node as TModel;

            //找到一个节点，currentNode将会移动到它的位置上去。
            ITreeNode nextNode = this.FindModelAtSameLevel(currentObject, isUp);

            //如果没有找到
            if (nextNode == null)
            {
                return;
            }

            //计算moveDistance
            int newIndex = this.IndexOf(nextNode as TModel);
            int oldIndex = currentObject.OrderNo;
            int moveDistance = newIndex - oldIndex;

            if (moveDistance > 0)
            {
                TModel lastChildOfCurrentObject = null;
                TModel lastChildOfNextNode = null;
                TreeHelper.TravelDepthFirst(currentObject, n => lastChildOfCurrentObject = n as TModel);
                TreeHelper.TravelDepthFirst(nextNode, n => lastChildOfNextNode = n as TModel);

                moveDistance = lastChildOfNextNode.OrderNo - lastChildOfCurrentObject.OrderNo;
            }

            if (moveDistance != 0)
            {
                this.MoveDistance(currentObject, moveDistance);

                this.SetOrderNoByIndex();
            }
        }
        public void ChangeNodeLevel(ITreeNode node, bool isUp)
        {
            TModel model = node as TModel;
            if (model == null) throw new ArgumentNullException("node");

            if (isUp)
            {
                this.LevelUp(model);
            }
            else
            {
                this.LevelDown(model);
            }
        }
        public ITreeNode CreateNode(ITreeNode targetNode, bool insertAsChild, bool beforeFirst)
        {
            if (targetNode == null) throw new ArgumentNullException("targetNode");

            //当前选中的对象
            var currentObject = targetNode as TModel;
            ITreeNode currentNode = currentObject as ITreeNode;
            if (currentNode == null) throw new ArgumentNullException("currentNode");

            this.EnsureIndices();
            this.EnsureObjectRelations();

            //建立新的对象
            //默认的位置就是链表的最后
            var newObject = this.AddNew() as TModel;
            ITreeNode newNode = newObject as ITreeNode;

            #region 设置新对象的父节点属性值

            //设置父节点
            if (insertAsChild)
            {
                newNode.ParentNode = currentNode;

                //如果是作为第一个孩子，则改变孩子节点集合的顺序。
                //默认是直接加到孩子节点的最后。
                if (beforeFirst)
                {
                    var children = currentNode.ChildrenNodes;
                    children.Remove(newNode);
                    children.Insert(0, newNode);
                }
            }
            else
            {
                //如果有父，则设置父节点
                if (currentNode.ParentNode != null)
                {
                    newNode.ParentNode = currentNode.ParentNode;
                }
            }

            #endregion

            #region 排序

            //以下是计算该节点从最后一位开始，需要移动到的目的的位置索引

            //设置新对象的OrderNo属性
            int currentIndex = this.IndexOf(currentObject);
            int newIndex = 0;

            //如果是插入孩子，直接在当前节点的后面插入
            if (insertAsChild)
            {
                //作为第一个孩子
                if (beforeFirst)
                {
                    newIndex = currentIndex + 1;
                }
                //作为最后一个孩子
                else
                {
                    //移动到最后一个子节点的后面一位

                    var allNodeCount = TreeHelper.CountTreeNode(currentNode);
                    //allNodeCount是含有newObject和currentNode的数，allNodeCount - 2是其它孩子节点的数
                    var oldChildrenCount = allNodeCount - 2;
                    //后面一位
                    newIndex = currentIndex + oldChildrenCount + 1;
                }
            }
            else
            {
                //如果在前面插入，则是当前节点的位置插入
                if (beforeFirst)
                {
                    newIndex = currentIndex;
                }
                //如果在后面插入，则计算所有子节点的个数，然后插入在最后一个子节点的后面
                else
                {
                    //插入在最后一个子节点的后面一位
                    var allNodeCount = TreeHelper.CountTreeNode(currentNode);
                    newIndex = currentIndex + allNodeCount;
                }
            }

            if (newIndex <= this.Count - 1)
            {
                this.Move(newObject, newIndex);

                this.SetOrderNoByIndex();
            }

            #endregion

            return newObject;
        }

        //protected virtual ITreeNode CreateChildInstance(TModel parent)
        //{
        //    return this.AddNew();
        //}

        private void AddModel(TModel model, bool recursivlyAddChildren)
        {
            if (model == null) throw new ArgumentNullException("model");

            this.EnsureIndices();

            TModel parent = null;
            bool findParent = model.Pid != null;

            #region 测试是否已经添加，并找到parent

            for (int i = 0, c = this.Count; i < c; i++)
            {
                var item = this[i];

                //已经存在，不再添加
                if (item == model)
                {
                    return;
                }

                //找到model的父节点
                if (findParent && parent == null && item.Id.Equals(model.Pid))
                {
                    parent = item;
                }
            }

            #endregion

            #region 加在集合的最后面

            if (recursivlyAddChildren)
            {
                TreeHelper.TravelDepthFirst(model, n =>
                {
                    var tempModel = n as TModel;

                    tempModel.OrderNo = this.NextOrderNo;
                    this.Add(tempModel);
                });
            }
            else
            {
                model.OrderNo = this.NextOrderNo;
                this.Add(model);
            }

            #endregion

            //如果父亲已经在集合里面了，就把这个节点移动到父亲的后面去。
            if (parent != null)
            {
                int destinationIndex = -1;

                #region 计算destinationIndex

                //parent已经是根节点
                if (parent.ParentNode == null)
                {
                    var nextRoot = this.FindRoot(parent, false);
                    //如果有下一个根节点，就应该移动到这个根节点的位置上
                    if (nextRoot != null)
                    {
                        destinationIndex = nextRoot.OrderNo;
                    }
                    //如果没有，则不需要移动。
                }
                else
                {
                    var nextSibling = this.FindSibling(parent, false);
                    //如果找到parent的下一个兄弟，就直接移动到这个兄弟节点的位置上
                    if (nextSibling != null)
                    {
                        destinationIndex = nextSibling.OrderNo;
                    }
                    //如果没有，就实施计算
                    else
                    {
                        int allNodeCountExcludeModel = parent.CountTreeNode() - model.CountTreeNode();
                        destinationIndex = parent.OrderNo + allNodeCountExcludeModel - 1;
                    }
                }

                #endregion

                //如果需要移动
                if (destinationIndex >= 0)
                {
                    int distance = destinationIndex - model.OrderNo;
                    if (distance != 0)
                    {
                        this.MoveDistance(model, distance);
                        this.SetOrderNoByIndex();
                    }
                }
            }
        }
        private void LevelUp(TModel node)
        {
            this.EnsureIndices();
            this.EnsureObjectRelations();

            //缓存原来的父节点
            ITreeNode oldParentNode = node.ParentNode;

            //父节点变上一级
            node.ParentNode = oldParentNode.ParentNode;

            //计算moveDistance
            //新的物理位置是在父节点的最后一个孩子后面
            int oldParentIndex = this.IndexOf(oldParentNode as TModel);
            int newIndex = oldParentIndex + TreeHelper.CountTreeNode(oldParentNode);
            int oldIndex = node.OrderNo;
            int moveDistance = newIndex - oldIndex;

            if (moveDistance != 0)
            {
                this.MoveDistance(node, moveDistance);

                this.SetOrderNoByIndex();
            }

            var newParentNode = node.ParentNode;
            if (newParentNode != null)
            {
                #region 排序ChildNodes

                var list = newParentNode.ChildrenNodes;
                if (list.Count > 1 &&
                    (list[list.Count - 2] as IOrderedObject).OrderNo > node.OrderNo//node的OrderNo并不是最大的
                    )
                {
                    var newChildIndex = list.Count - 1;
                    for (int i = 0, c = list.Count; i < c; i++)
                    {
                        var item = list[i] as IOrderedObject;
                        if (item.OrderNo > node.OrderNo)
                        {
                            newChildIndex = i;
                            break;
                        }
                    }

                    list.Remove(node);
                    list.Insert(newChildIndex, node);
                }

                #endregion
            }
        }
        private void LevelDown(TModel node)
        {
            this.EnsureIndices();
            this.EnsureObjectRelations();

            var currentNode = node as TModel;

            //上一个节点
            ITreeNode oldPrevNode = this.FindModelAtSameLevel(currentNode, true);

            //直接设置上一个节点为父节点，不需要更改OrderNo和Index
            currentNode.ParentNode = oldPrevNode;
        }
        /// <summary>
        /// 把一个节点及它的所有孩子，都向后移动指定的距离
        /// </summary>
        /// <param name="node"></param>
        /// <param name="moveDistance"></param>
        private void MoveDistance(TModel node, int moveDistance)
        {
            //如果是向前移动，则直接移动所有节点
            if (moveDistance < 0)
            {
                TreeHelper.TravelDepthFirst(node, (n) =>
                {
                    var model = n as TModel;
                    int modelNewIndex = model.OrderNo + moveDistance;
                    this.Move(model, modelNewIndex);
                });
            }
            //如果是向后移动，则应该先移动后面的
            else if (moveDistance > 0)
            {
                List<TModel> models = new List<TModel>();
                TreeHelper.TravelDepthFirst(node, n => models.Add(n as TModel));

                for (int i = models.Count - 1; i >= 0; i--)
                {
                    var model = models[i];
                    int modelNewIndex = model.OrderNo + moveDistance;
                    this.Move(model, modelNewIndex);
                }
            }
        }

        #endregion

        #region ITreeNodeCollection<C> Members

        public bool Sorted { get; private set; }
        public bool ObjectRelationsRuilt { get; private set; }
        public TreeNodeTravelType SortType
        {
            get
            {
                return TreeNodeTravelType.DepthFirst;
            }
            set
            {
                throw new NotSupportedException();
            }
        }

        public void RebuildObjectRelations()
        {
            TreeHelper.RebuildRelations(this);
        }
        public void EnsureObjectRelations()
        {
            if (this.ObjectRelationsRuilt == false)
            {
                this.RebuildObjectRelations();
                this.ObjectRelationsRuilt = true;
            }
        }
        public void SortByTree()
        {
            this.EnsureObjectRelations();

            var roots = TreeHelper.FindRootNodes(this);

            int index = 0;
            foreach (var item in roots)
            {
                TreeHelper.TravelDepthFirst(item, n =>
                {
                    this.Move(n, index);
                    index++;
                });
            }
        }
        public void EnsureSorted()
        {
            if (this.Sorted == false)
            {
                this.SortByTree();
                this.Sorted = true;
            }
        }
        public ITreeNode FindPrevSibling(ITreeNode node)
        {
            return this.FindSibling(node as TModel, true);
        }
        public ITreeNode FindNextSibling(ITreeNode node)
        {
            return this.FindSibling(node as TModel, false);
        }
        public ITreeNode[] FindRoots()
        {
            return TreeHelper.FindRootNodes(this);
        }
        public void AddNode(ITreeNode node, bool recursivlyAddChildren)
        {
            //注意:一个依赖上层的方法实现！
            this.AddModel(node as TModel, recursivlyAddChildren);
        }
        public ITreeNode FindNodeAtSameLevel(ITreeNode node, bool before)
        {
            return this.FindModelAtSameLevel(node as TModel, before);
        }
        //public ITreeNode CreateChildInstance(ITreeNode parent)
        //{
        //    return this.CreateChildInstance(parent as TModel);
        //}

        /// <summary>
        /// 找root的前/后一根节点
        /// </summary>
        /// <param name="root"></param>
        /// <param name="before"></param>
        /// <returns></returns>
        private TModel FindRoot(TModel root, bool before)
        {
            if (root == null) throw new ArgumentNullException("root");
            // RootPid不为空时也可以为根节点,所以不能加此判断
			//if (root.Pid != null) throw new ArgumentNullException("This value must be true!");

            var roots = this.Where(n => n.Pid == null).ToList();
            int indexInRoots = roots.IndexOf(root);
            int nextRootIndex = indexInRoots + (before ? -1 : 1);
            if (nextRootIndex >= 0 && nextRootIndex < roots.Count)
            {
                return roots[nextRootIndex];
            }

            return null;
        }
        /// <summary>
        /// 找的前/后一兄弟节点
        /// </summary>
        /// <param name="model"></param>
        /// <param name="before"></param>
        /// <returns></returns>
        private TModel FindSibling(TModel model, bool before)
        {
            if (model == null) throw new ArgumentNullException("node");

            this.EnsureObjectRelations();

            var parentNode = model.ParentNode;

            //如果有父节点，则计算兄弟节点
            if (parentNode != null)
            {
                //前一兄弟节点
                var children = parentNode.ChildrenNodes;
                int index = children.IndexOf(model) + (before ? -1 : 1);
                if (index >= 0 && index < children.Count)
                {
                    return children[index] as TModel;
                }
            }

            return null;
        }
        /// <summary>
        /// 找“同级”的前/后一节点
        /// </summary>
        /// <param name="model"></param>
        /// <param name="before"></param>
        /// <returns></returns>
        private TModel FindModelAtSameLevel(TModel model, bool before)
        {
            this.EnsureObjectRelations();

            if (model.ParentNode != null)
            {
                return this.FindSibling(model, before);
            }
            else
            {
                return this.FindRoot(model, before);
            }
        }

        //public ITreeNode FindPrevNode(ITreeNode node)
        //{
        //    if (node == null) throw new ArgumentNullException("node");

        //    var model = node as TModel;

        //    this.EnsureEntityRelations();

        //    var parentNode = node.ParentNode;
        //    if (parentNode != null)
        //    {
        //        var sibling = this.FindPrevSibling(node);
        //        if (sibling != null)
        //        {
        //            return sibling;
        //        }
        //    }

        //    #region 没有兄弟/没有父节点，计算前一节点的最上层父节点

        //    //找到前一节点的位置
        //    int index = this.IndexOf(model) - 1;
        //    if (index < 0)
        //    {
        //        return null;
        //    }

        //    //当list中index处节点的Pid值不为空，则向上寻找
        //    //考虑懒加载关系，这里使用Pid，而不是用ParentNode
        //    while (null != this[index].Pid)
        //    {
        //        index--;
        //        if (index < 0)
        //        {
        //            return null;
        //        }
        //    }

        //    //返回最上层的父节点
        //    return this[index];

        //    #endregion
        //}
        //public ITreeNode FindNextNode(ITreeNode node)
        //{
        //    if (node == null) throw new ArgumentNullException("node");

        //    var model = node as TModel;

        //    this.EnsureEntityRelations();

        //    var parentNode = node.ParentNode;
        //    if (parentNode != null)
        //    {
        //        var sibling = this.FindNextSibling(node);
        //        if (sibling != null)
        //        {
        //            return sibling;
        //        }
        //    }

        //    #region 没有兄弟/没有父节点，计算前一节点的最上层父节点

        //    //找到后一节点的位置
        //    int index = this.IndexOf(model) + 1;
        //    if (index > this.Count - 1)
        //    {
        //        return null;
        //    }

        //    //当list中index处节点的Pid值不为空，则向上寻找
        //    //考虑懒加载关系，这里使用Pid，而不是用ParentNode
        //    while (null != this[index].Pid)
        //    {
        //        index++;
        //        if (index > this.Count - 1)
        //        {
        //            return null;
        //        }
        //    }

        //    //返回最上层的父节点
        //    return this[index];

        //    #endregion
        //}

        #endregion

        #region IOrderedObjectCollection<C> Members

        public int NextOrderNo
        {
            get
            {
                return this.Count;
            }
        }

        public void SortByOrderNo()
        {
            var cachedArray = this.ToArray();

            for (int i = 0, c = cachedArray.Length; i < c; i++)
            {
                var item = cachedArray[i];
                this.Move(item, item.OrderNo);
            }
        }
        public void SetOrderNoByIndex()
        {
            for (int i = 0, c = this.Count; i < c; i++)
            {
                var item = this[i];
                item.OrderNo = i;
            }
        }
        public void MoveNode(IOrderedObject node, bool isUp)
        {
            //注意:一个依赖上层的方法实现！
            this.MoveNode(node as ITreeNode, isUp);
        }

        #endregion

        #region 更改集合元素物理顺序的唯一API

        #region ISimpleMovableCollection<C> Members

        /// <summary>
        /// 这里的Move在移动时不是直接对换相应位置的节点，
        /// 而是中间的节点会一个挨着一个的移动。
        /// 
        /// 这方法作为最底层的方法，类中的所有方法的实现都是基于这种Move，
        /// 一旦改变，整个类都可能需要重写！！！
        /// </summary>
        /// <param name="item"></param>
        /// <param name="newIndex"></param>
        public void Move(TModel item, int newIndex)
        {
            if (item == null) throw new ArgumentNullException("item");
            if (!(newIndex < this.Count)) throw new Exception("This value must be true!");

            if (this[newIndex] != item)
            {
                item.Move(newIndex);
            }
        }
        public void Move(int oldIndex, int newIndex)
        {
            this.Move(this[oldIndex], newIndex);
        }
        public void Move(object item, int newIndex)
        {
            this.Move(item as TModel, newIndex);
        }

        #endregion

        #endregion

        #endregion
    }
}